package com.cocolover2.andbase.views.refreshview;

import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.Scroller;

import com.cocolover2.andbase.R;

/**
 * 下拉刷新布局
 */

public class PullRefreshLayout extends ViewGroup {

    private static final int DEFAULT_SWIPING_TO_REFRESH_TO_DEFAULT_SCROLLING_DURATION = 200;

    private static final int DEFAULT_RELEASE_TO_REFRESHING_SCROLLING_DURATION = 200;

    private static final int DEFAULT_REFRESH_COMPLETE_DELAY_DURATION = 1000;

    private static final int DEFAULT_REFRESH_COMPLETE_TO_DEFAULT_SCROLLING_DURATION = 500;

    private static final int DEFAULT_DEFAULT_TO_REFRESHING_SCROLLING_DURATION = 800;

    /**
     * 下拉阻力系数
     * how hard to drag
     */
    private static final float DEFAULT_DRAG_RATIO = 0.5f;

    private static final int INVALID_POINTER = -1;

    private static final int INVALID_COORDINATE = -1;


    //下拉-->原始的滚动时间
    private int mSwipingToDefaultScrollingDuration = DEFAULT_SWIPING_TO_REFRESH_TO_DEFAULT_SCROLLING_DURATION;
    //释放--->正在刷新
    private int mReleaseToRefreshingScrollingDuration = DEFAULT_RELEASE_TO_REFRESHING_SCROLLING_DURATION;
    //刷新完成的结果展示的时间
    private int mRefreshCompleteDelayDuration = DEFAULT_REFRESH_COMPLETE_DELAY_DURATION;
    //刷新完成--->原始
    private int mRefreshCompleteToDefaultScrollingDuration = DEFAULT_REFRESH_COMPLETE_TO_DEFAULT_SCROLLING_DURATION;
    //原始--->正在刷新
    private int mAutoRefreshScrollingDuration = DEFAULT_DEFAULT_TO_REFRESHING_SCROLLING_DURATION;

    private float mDragRatio = DEFAULT_DRAG_RATIO;


    private int mTouchSlop;

    private final int SCREEN_HEIGHT;
    //下拉过程触发刷新的便宜量
    private float mRefreshTriggerOffset;

    private boolean isSetRefreshTrigger = false;

    private float mRefreshFinalDragOffset;

    private int mStyle = STYLE.CLASSIC;

    private boolean mRefreshEnabled = true;

    private View mHeaderView, mTargetView;
    //下拉布局的实际高度,一般比mRefreshTriggerOffset高
    private int mHeaderHeight;
    private int mHeaderOffset;
    private int mTargetOffset;


    private float mLastY;
    private float mLastX;
    private boolean mAutoRefresh = false;
    private RefreshCallBack mRefreshCallBack;

    private int mStatus = STATUS.STATUS_DEFAULT;
    //
    private AutoScrollerManager mAutoScrollerManager;

    private OnRefreshListener mOnRefreshListener;

    /**
     * init touch action down point.y
     */
    private float mInitDownY;
    private float mInitDownX;
    /**
     * action touch pointer's id
     */
    private int mActivePointerId;


    /**
     * the style enum
     */
    public static final class STYLE {
        //经典模式,刷新布局在底部
        public static final int CLASSIC = 0;
        //悬浮模式,刷新布局悬浮在内容上面
        public static final int ABOVE = 1;
    }

    public PullRefreshLayout(Context context) {
        this(context, null);
    }

    public PullRefreshLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);

    }

    public PullRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        SCREEN_HEIGHT = getResources().getDisplayMetrics().heightPixels;
        mAutoScrollerManager = new AutoScrollerManager();

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.PullRefreshLayout);
        try {
            mSwipingToDefaultScrollingDuration = array.getInt(R.styleable.PullRefreshLayout_duration_swipe_default, DEFAULT_SWIPING_TO_REFRESH_TO_DEFAULT_SCROLLING_DURATION);
            mReleaseToRefreshingScrollingDuration = array.getInt(R.styleable.PullRefreshLayout_duration_release_refreshing, DEFAULT_RELEASE_TO_REFRESHING_SCROLLING_DURATION);
            mRefreshCompleteDelayDuration = array.getInt(R.styleable.PullRefreshLayout_duration_refresh_completed_delay, DEFAULT_REFRESH_COMPLETE_DELAY_DURATION);
            mRefreshCompleteToDefaultScrollingDuration = array.getInt(R.styleable.PullRefreshLayout_duration_completed_default, DEFAULT_REFRESH_COMPLETE_TO_DEFAULT_SCROLLING_DURATION);
            mAutoRefreshScrollingDuration = array.getInt(R.styleable.PullRefreshLayout_duration_default_refreshing, DEFAULT_DEFAULT_TO_REFRESHING_SCROLLING_DURATION);
            mDragRatio = array.getFloat(R.styleable.PullRefreshLayout_drag_ratio, DEFAULT_DRAG_RATIO);

            mStyle = array.getInt(R.styleable.PullRefreshLayout_style, STYLE.CLASSIC);

            mRefreshTriggerOffset = array.getDimension(R.styleable.PullRefreshLayout_refresh_trigger_offset, SCREEN_HEIGHT / 8);
            mRefreshFinalDragOffset = array.getDimension(R.styleable.PullRefreshLayout_refresh_final_trigger_offset, 0);
        } finally {
            array.recycle();
        }


    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        final int childNum = getChildCount();
        if (childNum == 0) {
            return;
        } else if (0 < childNum && childNum < 3) {
            mHeaderView = findViewById(R.id.pullrefresh_headview);
            mTargetView = findViewById(R.id.pullrefresh_targetview);
        } else {
            throw new IllegalStateException("Children num must equal or less than 2");
        }
        if (mTargetView == null) {
            return;
        }
        if (mHeaderView != null && mHeaderView instanceof OnSwipeTriggerListener) {
            mHeaderView.setVisibility(GONE);
            mRefreshCallBack = new RefreshCallBack();
        }
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // header
        if (mHeaderView != null) {
            measureChildWithMargins(mHeaderView, widthMeasureSpec, 0, heightMeasureSpec, 0);
            MarginLayoutParams lp = ((MarginLayoutParams) mHeaderView.getLayoutParams());
            mHeaderHeight = mHeaderView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            //当头部高度小于屏幕的一半时,认为头部布局的高度是固定值,如果不是时,就认为是头部布局是满屏的,此时会使用默认值
            if (!isSetRefreshTrigger && mHeaderHeight < SCREEN_HEIGHT / 2 && mRefreshTriggerOffset < mHeaderHeight) {
                mRefreshTriggerOffset = mHeaderHeight;
            }
        }
        // target
        if (mTargetView != null) {
            measureChildWithMargins(mTargetView, widthMeasureSpec, 0, heightMeasureSpec, 0);
        }
    }


    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        layoutChildren();

    }

    private void layoutChildren() {
        final int paddingLeft = getPaddingLeft();
        final int paddingTop = getPaddingTop();
        if (mTargetView == null) {
            return;
        }
        layoutHeadView(paddingLeft, paddingTop);
        layoutTagerView(paddingLeft, paddingTop);

        if (mStyle == STYLE.CLASSIC
                || mStyle == STYLE.ABOVE) {
            if (mHeaderView != null) {
                mHeaderView.bringToFront();
            }
        }
    }


    private void layoutHeadView(int paddingLeft, int paddingTop) {
        // layout header
        if (mHeaderView != null) {
            final View headerView = mHeaderView;
            MarginLayoutParams lp = (MarginLayoutParams) headerView.getLayoutParams();
            final int headerLeft = paddingLeft + lp.leftMargin;
            final int headerTop;
            switch (mStyle) {
                case STYLE.CLASSIC:
                    // classic
                    headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
                    break;
                case STYLE.ABOVE:
                    // classic
                    headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
                    break;
                default:
                    // classic
                    headerTop = paddingTop + lp.topMargin - mHeaderHeight + mHeaderOffset;
                    break;
            }

            final int headerRight = headerLeft + headerView.getMeasuredWidth();
            final int headerBottom = headerTop + headerView.getMeasuredHeight();

            headerView.layout(headerLeft, headerTop, headerRight, headerBottom);
        }

    }

    private void layoutTagerView(int paddingLeft, int paddingTop) {
        // layout target
        if (mTargetView != null) {
            final View targetView = mTargetView;
            MarginLayoutParams lp = (MarginLayoutParams) targetView.getLayoutParams();
            final int targetLeft = paddingLeft + lp.leftMargin;
            final int targetTop;
            switch (mStyle) {
                case STYLE.CLASSIC:
                    // classic
                    targetTop = paddingTop + lp.topMargin + mTargetOffset;
                    break;
                case STYLE.ABOVE:
                    // above
                    targetTop = paddingTop + lp.topMargin;
                    break;
                default:
                    targetTop = paddingTop + lp.topMargin + mTargetOffset;
                    break;
            }
            final int targetRight = targetLeft + targetView.getMeasuredWidth();
            final int targetBottom = targetTop + targetView.getMeasuredHeight();
            targetView.layout(targetLeft, targetTop, targetRight, targetBottom);
        }

    }

    public void setAutoRefreshScrollingDuration(int duration) {
        mAutoRefreshScrollingDuration = duration;
    }

    public void setRefreshCompleteDelayDuration(int duration) {
        mRefreshCompleteDelayDuration = duration;
    }

    public void setSwipingToDefaultScrollingDuration(int duration) {
        mSwipingToDefaultScrollingDuration = duration;
    }

    public void setReleaseToRefreshingScrollingDuration(int duration) {
        mReleaseToRefreshingScrollingDuration = duration;
    }

    public void setRefreshCompleteToDefaultScrollingDuration(int duration) {
        mRefreshCompleteToDefaultScrollingDuration = duration;
    }

    public void setDragRatio(float dragRatio) {
        mDragRatio = dragRatio;
    }

    public void setRefreshEnabled(boolean refreshEnabled) {
        mRefreshEnabled = refreshEnabled;
    }

    public void setRefreshTriggerOffset(float refreshTriggerOffset) {
        isSetRefreshTrigger = true;
        mRefreshTriggerOffset = refreshTriggerOffset;
    }

    public void setRefreshFinalDragOffset(int refreshFinalDragOffset) {
        mRefreshFinalDragOffset = refreshFinalDragOffset;
    }

    /**
     * @param style
     * @see STYLE
     */
    public void setStyle(int style) {
        mStyle = style;
    }

    public static class LayoutParams extends MarginLayoutParams {

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        @SuppressWarnings({"unused"})
        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new PullRefreshLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    @Override
    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        return new PullRefreshLayout.LayoutParams(p);
    }

    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new PullRefreshLayout.LayoutParams(getContext(), attrs);
    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (!mRefreshEnabled)
            return super.dispatchTouchEvent(ev);
        final int action = MotionEventCompat.getActionMasked(ev);
        switch (action) {
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // swipeToRefresh -> finger up -> finger down if the status is still swipeToRefresh
                // in onInterceptTouchEvent ACTION_DOWN event will stop the scroller
                // if the event pass to the child view while ACTION_MOVE(condition is false)
                // in onInterceptTouchEvent ACTION_MOVE the ACTION_UP or ACTION_CANCEL will not be
                // passed to onInterceptTouchEvent and onTouchEvent. Instead It will be passed to
                // child view's onTouchEvent. So we must deal this situation in dispatchTouchEvent
                onActivePointerUp();
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * on active finger up
     */
    private void onActivePointerUp() {

        if (STATUS.isSwipingToRefresh(mStatus)) {
            // 下拉状态
            mAutoScrollerManager.scrollSwipingToRefreshToDefault();
        } else if (STATUS.isReleaseToRefresh(mStatus)) {
            mAutoScrollerManager.scrollReleaseToRefreshToRefreshing();
            // 释放状态
            mRefreshCallBack.onRelease();
        } else if (STATUS.isRefreshing(mStatus)) {
            if (mTargetOffset > mRefreshTriggerOffset)
                mAutoScrollerManager.scrollReleaseToRefreshToRefreshing();
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (!mRefreshEnabled)
            return super.onInterceptTouchEvent(event);
        final int action = MotionEventCompat.getActionMasked(event);
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = MotionEventCompat.getPointerId(event, 0);
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                // if it isn't an ing status or default status
                if (STATUS.isSwipingToRefresh(mStatus) || STATUS.isReleaseToRefresh(mStatus)) {
//                    // abort autoScrolling, not trigger the method #autoScrollFinished()
                    if (!mAutoRefresh) {
                        mAutoScrollerManager.abortIfRunning();
                        return true;
                    }
                }
                break;

            case MotionEvent.ACTION_MOVE:

                if (mActivePointerId == INVALID_POINTER) {
                    return false;
                }
                float y = getMotionEventY(event, mActivePointerId);
                float x = getMotionEventX(event, mActivePointerId);
                final float yInitDiff = y - mInitDownY;
                final float xInitDiff = x - mInitDownX;
                mLastY = y;
                mLastX = x;
                final boolean moved = Math.abs(yInitDiff) > Math.abs(xInitDiff);
                //拦截的条件:1想要下拉刷新,2.正在刷新中拖动布局且不是悬浮模式
                final boolean triggerCondition = (yInitDiff > 0 && moved && onCheckCanRefresh())
                        || (STATUS.isRefreshStatus(mStatus) && moved && mStyle != STYLE.ABOVE && mTargetOffset > 0);
                if (triggerCondition) {
                    return true;
                }
                break;

            case MotionEvent.ACTION_POINTER_UP:
                //多指操作时,离开屏幕记录位置
                onSecondaryPointerUp(event);
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                //单指操作离开后,位置在操作过程中已经记录过此处不需要记录
                mActivePointerId = INVALID_POINTER;
                break;
        }
        return super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!mRefreshEnabled)
            return super.onTouchEvent(event);

        final int action = MotionEventCompat.getActionMasked(event);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = MotionEventCompat.getPointerId(event, 0);
                return true;

            case MotionEvent.ACTION_MOVE:
                // take over the ACTION_MOVE event from SwipeToLoadLayout#onInterceptTouchEvent()
                // if condition is true
                final float y = getMotionEventY(event, mActivePointerId);
                final float x = getMotionEventX(event, mActivePointerId);

                final float yDiff = y - mLastY;
                final float xDiff = x - mLastX;
                mLastY = y;
                mLastX = x;

                if (Math.abs(xDiff) > Math.abs(yDiff) && Math.abs(xDiff) > mTouchSlop) {
                    return false;
                }

                if (STATUS.isStatusDefault(mStatus)) {
                    if (yDiff > 0 && onCheckCanRefresh()) {
                        setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
                        mRefreshCallBack.onPrepare();
                    }
                }

                if ((STATUS.isSwipingToRefresh(mStatus) || STATUS.isReleaseToRefresh(mStatus))) {
                    if (mTargetOffset <= 0) {
                        setStatus(STATUS.STATUS_DEFAULT);
                        fixCurrentStatusLayout(false);
                    } else if (mTargetOffset >= mRefreshTriggerOffset) {
                        setStatus(STATUS.STATUS_RELEASE_TO_REFRESH);
                    } else {
                        setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
                    }
                } else if (STATUS.isRefreshing(mStatus)) {//处理正在刷新是拖动布局的情况
                    fixCurrentStatusLayout(false);
                }

                /*
                * 1.当不能向上滑动时
                * 2.当是悬浮模式时,不在正在刷新状态
                * 满足以上情况时,才可用手指拖动布局,触发下拉刷新布局
                * */
                if (!canChildScrollUp() && !(STATUS.isRefreshing(mStatus) && mStyle == STYLE.ABOVE)) {
                    fingerScroll(yDiff);
                }
                if (mTargetOffset <= 0)
                    mTargetView.onTouchEvent(event);
                return true;
            case MotionEvent.ACTION_POINTER_DOWN:
                final int pointerIndex = MotionEventCompat.getActionIndex(event);
                final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
                if (pointerId != INVALID_POINTER) {
                    mActivePointerId = pointerId;
                }
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                break;

            case MotionEvent.ACTION_POINTER_UP:
                onSecondaryPointerUp(event);
                mInitDownY = mLastY = getMotionEventY(event, mActivePointerId);
                mInitDownX = mLastX = getMotionEventX(event, mActivePointerId);
                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (mActivePointerId == INVALID_POINTER) {
                    return false;
                }
                mActivePointerId = INVALID_POINTER;
                break;
            default:
                break;
        }
        return super.onTouchEvent(event);
    }

    /**
     * @param isAutoFix 在正在刷新的状态下才有效
     */
    private void fixCurrentStatusLayout(boolean isAutoFix) {
        if (STATUS.isRefreshing(mStatus)) {
            if (isAutoFix) {
                mTargetOffset = (int) (mRefreshTriggerOffset + 0.5f);
                mHeaderOffset = mTargetOffset;
            } else if (mTargetOffset < 0) {
                mTargetOffset = 0;
                mHeaderOffset = 0;
            }
            layoutChildren();
            invalidate();
        } else if (STATUS.isStatusDefault(mStatus)) {
            mTargetOffset = 0;
            mHeaderOffset = 0;
            layoutChildren();
            invalidate();
        }
    }


    private float getMotionEventY(MotionEvent event, int activePointerId) {
        final int index = MotionEventCompat.findPointerIndex(event, activePointerId);
        if (index < 0) {
            return INVALID_COORDINATE;
        }
        return MotionEventCompat.getY(event, index);
    }

    private float getMotionEventX(MotionEvent event, int activePointId) {
        final int index = MotionEventCompat.findPointerIndex(event, activePointId);
        if (index < 0) {
            return INVALID_COORDINATE;
        }
        return MotionEventCompat.getX(event, index);
    }

    private boolean onCheckCanRefresh() {
        return mRefreshEnabled && !canChildScrollUp() && mHeaderView != null && mRefreshTriggerOffset > 0;
    }

    protected boolean canChildScrollUp() {
        if (android.os.Build.VERSION.SDK_INT < 14) {
            if (mTargetView instanceof AbsListView) {
                final AbsListView absListView = (AbsListView) mTargetView;
                return absListView.getChildCount() > 0
                        && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
                        .getTop() < absListView.getPaddingTop());
            } else {
                return ViewCompat.canScrollVertically(mTargetView, -1) || mTargetView.getScrollY() > 0;
            }
        } else {
            return ViewCompat.canScrollVertically(mTargetView, -1);
        }
    }

    private void onSecondaryPointerUp(MotionEvent ev) {
        final int pointerIndex = MotionEventCompat.getActionIndex(ev);
        final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
        }
    }

    /**
     * 手指控制视图滚动
     */
    private void fingerScroll(float yDiff) {
        float yScrolled = yDiff * mDragRatio;


        final float tmpTargetOffset = yScrolled + mTargetOffset;

        //滑动最大距离
        if (mRefreshFinalDragOffset >= mRefreshTriggerOffset && tmpTargetOffset > mRefreshFinalDragOffset) {
            yScrolled = mRefreshFinalDragOffset - mTargetOffset;
        }

        if (STATUS.isReleaseToRefresh(mStatus) || STATUS.isSwipingToRefresh(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, false, false);
            //处理在正在刷新状态时,用手指进行滑动屏幕的操作
        } else if (STATUS.isRefreshing(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, true, false);
        }

        //当处于刷成完成状态时,手指滚动屏幕失效
        if (!STATUS.isRefreshCompleted(mStatus))
            invalidateScoll(yScrolled);
    }

    private void autoScroll(final float yScrolled) {
        if (STATUS.isSwipingToRefresh(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, false, true);
        } else if (STATUS.isReleaseToRefresh(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, false, true);
        } else if (STATUS.isRefreshing(mStatus)) {
            mRefreshCallBack.onMove(mTargetOffset, mRefreshTriggerOffset, true, true);
        }
        //防止在正在刷新状态或者释放触发刷新状态时,自动滚动到正在刷新界面时,距离小于设置的初始间距造成的闪烁
        if (STATUS.isRefreshing(mStatus) || STATUS.isReleaseToRefresh(mStatus)) {
            if (mTargetOffset + yScrolled < mRefreshTriggerOffset)
                return;
        }
        invalidateScoll(yScrolled);
    }

    /**
     * 刷新当前布局
     *
     * @param yScrolled
     */
    private void invalidateScoll(final float yScrolled) {
        if (yScrolled == 0) {
            return;
        }
        mTargetOffset += yScrolled;

        if (mTargetOffset < 0) {
            mTargetOffset = 0;
        }
        mHeaderOffset = mTargetOffset;

        layoutChildren();
        invalidate();
    }


    private void setStatus(int status) {
        mStatus = status;
    }

    public void setOnRefreshListener(OnRefreshListener listener) {
        mOnRefreshListener = listener;
    }


    /**
     * 刷新的整体状态有4种
     * 1.默认状态
     * 2.下拉状态
     * 3.释放状态
     * 4.正在刷新状态
     */
    private final static class STATUS {
        private static final int STATUS_REFRESH_COMPLETED = -4;
        //正在刷新状态
        private static final int STATUS_REFRESHING = -3;
        //释放状态
        private static final int STATUS_RELEASE_TO_REFRESH = -2;
        //下拉还没有到达释放状态的过程状态
        private static final int STATUS_SWIPING_TO_REFRESH = -1;
        //原始状态
        private static final int STATUS_DEFAULT = 0;


        private static boolean isRefreshing(final int status) {
            return status == STATUS.STATUS_REFRESHING;
        }

        private static boolean isRefreshStatus(final int status) {
            return status < STATUS_DEFAULT;
        }

        private static boolean isReleaseToRefresh(final int status) {
            return status == STATUS.STATUS_RELEASE_TO_REFRESH;
        }

        private static boolean isSwipingToRefresh(final int status) {
            return status == STATUS.STATUS_SWIPING_TO_REFRESH;
        }

        private static boolean isStatusDefault(final int status) {
            return status == STATUS.STATUS_DEFAULT;
        }

        private static boolean isRefreshCompleted(final int status) {
            return status == STATUS.STATUS_REFRESH_COMPLETED;
        }
    }

    /**
     * 下拉刷新过程各种状态的回调
     */
    class RefreshCallBack implements OnSwipeTriggerListener {
        OnSwipeTriggerListener mHeaderViewTrigger;

        public RefreshCallBack() {
            if (mHeaderView != null && mHeaderView instanceof OnSwipeTriggerListener) {
                mHeaderViewTrigger = (OnSwipeTriggerListener) mHeaderView;
            } else {
                throw new IllegalArgumentException("HeaderView is null or not instanceof OnSwipeTriggerListener");
            }
        }

        public void onPrepare() {
            if (mHeaderView.getVisibility() != VISIBLE)
                mHeaderView.setVisibility(VISIBLE);
        }

        @Override
        public void onMove(int y, float refreshTriggerOffset, boolean isRefreshing, boolean automatic) {
            if (mHeaderView.getVisibility() != VISIBLE)
                mHeaderView.setVisibility(VISIBLE);
            mHeaderViewTrigger.onMove(y, refreshTriggerOffset, isRefreshing, automatic);
        }

        @Override
        public void onRelease() {
            mHeaderViewTrigger.onRelease();
        }

        @Override
        public void onRefresh() {
            mHeaderViewTrigger.onRefresh();
            if (mOnRefreshListener != null)
                mOnRefreshListener.onRefresh();
        }

        @Override
        public void onComplete(String statusMsg) {
            mHeaderViewTrigger.onComplete(statusMsg);
        }

        @Override
        public void onReset() {
            mHeaderViewTrigger.onReset();
            mHeaderView.setVisibility(GONE);
        }
    }

    /**
     * 自动滚动结束后的状态处理
     */
    private void autoScrollFinished() {
        if (STATUS.isReleaseToRefresh(mStatus)) {
            setStatus(STATUS.STATUS_REFRESHING);
            fixCurrentStatusLayout(true);
            mRefreshCallBack.onRefresh();
        } else if (STATUS.isRefreshing(mStatus)) {
            fixCurrentStatusLayout(true);
        } else if (STATUS.isSwipingToRefresh(mStatus)) {
            if (!mAutoRefresh) {
                setStatus(STATUS.STATUS_DEFAULT);
                fixCurrentStatusLayout(true);
                mRefreshCallBack.onReset();
            } else {
                mAutoRefresh = false;
                setStatus(STATUS.STATUS_REFRESHING);
                fixCurrentStatusLayout(true);
                mRefreshCallBack.onRefresh();
            }
        } else if (STATUS.isRefreshCompleted(mStatus)) {
            setStatus(STATUS.STATUS_DEFAULT);
            fixCurrentStatusLayout(true);
            mRefreshCallBack.onReset();
        }

    }

    /**
     * 刷新完成
     */
    public void refreshCompleted(String statusMsg) {
        if (!mRefreshEnabled || mHeaderView == null) {
            return;
        }
        setStatus(STATUS.STATUS_REFRESH_COMPLETED);
        mRefreshCallBack.onComplete(statusMsg);
        postDelayed(new Runnable() {
            @Override
            public void run() {
                mAutoScrollerManager.scrollRefreshingToDefault();
            }
        }, mRefreshCompleteDelayDuration);
    }

    //自动刷新
    public void autoRefresh() {
        if (!mRefreshEnabled || mHeaderView == null) {
            return;
        }
        mAutoRefresh = true;
        post(new Runnable() {
            @Override
            public void run() {
                if (STATUS.isStatusDefault(mStatus)) {
                    setStatus(STATUS.STATUS_SWIPING_TO_REFRESH);
                    mAutoScrollerManager.scrollDefaultToRefreshing();
                }
            }
        });

    }


    /**
     * 自动滚动管理者
     */
    private final class AutoScrollerManager {
        private Scroller mScroller;

        private int mmLastY;

        private boolean mRunning = false;

        private boolean mAbort = false;

        private boolean mIsFrist;

        public AutoScrollerManager() {
            mScroller = new Scroller(getContext());
        }

        private final Runnable autoScrollRunnable = new Runnable() {
            @Override
            public void run() {

                int currY = mScroller.getCurrY();
                if (mIsFrist && currY == mmLastY) {//由于mScroller会记录上一次的Y的坐标,这里重置一下,防止滚动时,界面闪烁
                    currY = mmLastY = 0;
                    mIsFrist = false;
                }
                final int yDiff = currY - mmLastY;

                if (!mScroller.computeScrollOffset() || mScroller.isFinished()) {
                    finishScorll();
                } else {
                    mmLastY = currY;
                    PullRefreshLayout.this.autoScroll(yDiff);
                    post(this);
                }
            }
        };

        private void finishScorll() {
            mRunning = false;
            removeCallbacks(autoScrollRunnable);
            // if abort by user, don't call
            if (!mAbort) {
                autoScrollFinished();
            }
        }

        /**
         * abort scroll if it is scrolling
         */
        public void abortIfRunning() {
            if (mRunning) {
                if (!mScroller.isFinished()) {
                    mAbort = true;
                    mScroller.forceFinished(true);
                }
                finishScorll();
                mAbort = false;
            }
        }

        private void autoScroll(int yScrolled, int duration) {
            removeCallbacks(autoScrollRunnable);
            mmLastY = mScroller.getCurrY();
            mIsFrist = true;
            if (!mScroller.isFinished()) {
                mScroller.forceFinished(true);
            }
            mScroller.startScroll(0, 0, 0, yScrolled, duration);
            post(autoScrollRunnable);
            mRunning = true;
        }

        //原始状态——->正在刷新状态(用于自动刷新)
        public void scrollDefaultToRefreshing() {
            autoScroll((int) (mRefreshTriggerOffset + 0.5f), mAutoRefreshScrollingDuration);
        }

        //下拉状态--->原始状态
        public void scrollSwipingToRefreshToDefault() {
            autoScroll(-mHeaderOffset, mSwipingToDefaultScrollingDuration);
        }

        //释放状态--->正在刷新状态
        public void scrollReleaseToRefreshToRefreshing() {
            autoScroll((int) (mRefreshTriggerOffset + 0.5f) - mHeaderOffset, mReleaseToRefreshingScrollingDuration);
        }

        //正在刷新--->原始状态
        public void scrollRefreshingToDefault() {
            autoScroll(-mHeaderOffset, mRefreshCompleteToDefaultScrollingDuration);
        }

    }
}


